#include "fig_enemy_collection.h"
#include "fig_enemy_craft.h"
#include "fig_enemy_pathcraft.h"
#include "fig_enemy_miniboss.h"
#include "fig_enemy_boss.h"
#include "fig_enemy_triangle.h"
#include "fig_enemynormal_backattacker.h"

#include "fig_miniboss_hulk.h"
#include "fig_miniboss_cobra.h"
#include "fig_miniboss_meganito.h"
#include "fig_miniboss_fox.h"
#include "fig_miniboss_pron.h"
#include "fig_miniboss_shark.h"
#include "fig_miniboss_plato.h"
#include "fig_miniboss_hadiez.h"
#include "fig_miniboss_bomber.h"
#include "fig_miniboss_wolf.h"  

#include "fig_boss_hummer.h"
#include "fig_boss_beast.h"
#include "fig_boss_boffer.h"
#include "fig_boss_destoryer.h"
#include "fig_boss_gyver.h"
#include "fig_boss_eagle.h"
#include "fig_boss_u14.h"

#include "fig_enemy_test.h"
#include "fig_pickup.h"
#include "fig_spacerock.h"
#include "fig_enemy_dragon.h"
#include "fig_enemy_formationcraft.h"


#include "num/rand.h"
#include "util/mmgr.h"		    // Needs to come in early
#include "util/common_macros.h"		// macros
#include "util/log.h"		    // logging
#include "util/timer.h"		    // logging

FIGEnemyCollection::FIGEnemyCollection(FIGEnemyCraft::ENEMY_TYPES Type,
									   unsigned long NameCRC
									   )  : m_Type(Type),
											m_NameCRC(NameCRC)
{
	
}




void		FIGEnemyCollection::RenderDecal(const math::Vec2& Offset,float Scale)
{
	for(unsigned int i = 0; i < m_Enemies.size(); i++)
	{
		FIGEnemyCraft*  pEnemyCraft = m_Enemies[i];
		if(pEnemyCraft->GetEnemeyType() == FIGEnemyCraft::ENEMY_TYPES_SPACEROCK_DECAL)
			pEnemyCraft->Render(Offset, Scale);
	}
}


void		FIGEnemyCollection::Render(const math::Vec2& Offset,float Scale)
{
	for(unsigned int i = 0; i < m_Enemies.size(); i++)
	{
		FIGEnemyCraft*  pEnemyCraft = m_Enemies[i];
		if(pEnemyCraft->GetEnemeyType() != FIGEnemyCraft::ENEMY_TYPES_SPACEROCK_DECAL)
		{
			pEnemyCraft->Render(Offset, Scale);
			pEnemyCraft->RenderSFX(Offset, Scale);
		}
		
	}
}

void		FIGEnemyCollection::RenderShadow(const math::Vec2& Offset,float Scale)
{
	for(unsigned int i = 0; i < m_Enemies.size(); i++)
	{
		FIGEnemyCraft*  EnemyCraft = m_Enemies[i];
		EnemyCraft->RenderShadow(Offset, Scale);
	}
}

void		FIGEnemyCollection::RenderDebug(const math::Vec2& Offset,float Scale)
{
	for(unsigned int i = 0; i < m_Enemies.size(); i++)
	{
		FIGEnemyCraft*  EnemyCraft = m_Enemies[i];
		EnemyCraft->RenderDebug(Offset, Scale);
	}
}

void		FIGEnemyCollection::Tick(float dt)
{
	for(unsigned int i = 0; i < m_Enemies.size(); i++)
	{
		FIGEnemyCraft*  EnemyCraft = m_Enemies[i];
		EnemyCraft->Tick(dt);
	}
}


void		FIGEnemyCollection::Clear()
{
	int C = (int)m_Enemies.size();
	for( int i = C - 1; i >= 0; i--)
	{
		FIGEnemyCraft*  pEnemyCraft = m_Enemies[i];
		pEnemyCraft->Clear();
		UTIL_SAFE_DELETE(pEnemyCraft);
	}
	m_Enemies.resize(0);
}
	

void		FIGEnemyCollection::Spawn(const FIGLevel::EnemyInfo* pEnemyInfo )
{
	int Index = 0;
	bool	bSpawn =false;
	FIGEnemyCraft*  pEnemyCraft;
	

	int SpawnPickupIndex = 0;
	FIGPickup::PICKUP_TYPES	TempPickup = FIGPickup::PICKUP_TYPE_NONE;
	if(pEnemyInfo->Count > 0 && pEnemyInfo->SpawnTypeEnumInt > 0)
	{
		// only one obj will spawn that pickup
		SpawnPickupIndex = num::RAND32::Instance().RandInt(0,pEnemyInfo->Count-1);
		
	}

	while(Index < pEnemyInfo->Count)
	{
		pEnemyCraft = NULL;
		
		bSpawn =false;
		for( int i = 0; i < (int)m_Enemies.size(); i++)
		{
			 pEnemyCraft = m_Enemies[i];
			if(pEnemyCraft->IsReadyToSpawn())
			{
				
				bSpawn = true;
				i = (int)m_Enemies.size();
			}
		}

		if(!bSpawn)
		{
			
			pEnemyCraft = CreateEnemyCraft(pEnemyInfo);
			if(pEnemyCraft)
			{
				m_Enemies.push_back(pEnemyCraft);
				if(pEnemyInfo->Name.size() > 0)
					pEnemyCraft->Load(pEnemyInfo->Name);
				
			}
		}

		if(pEnemyCraft)
		{
			if(SpawnPickupIndex == Index)
				TempPickup = (FIGPickup::PICKUP_TYPES)pEnemyInfo->SpawnTypeEnumInt;
			else
				TempPickup = FIGPickup::PICKUP_TYPE_NONE;
			pEnemyCraft->InitSpawning(
										pEnemyInfo->DelaySpawn * (Index + 1),
										pEnemyInfo->SpawnPositionX,
										TempPickup

										);
			
			if( (FIGFlyingPath::PATH_TYPE)pEnemyInfo->FlyingPathEnumInt > FIGFlyingPath::PATH_NONE )
			{
				((FIGEnemyPathCraft*)pEnemyCraft)->SetFlyPathInfo(pEnemyInfo,Index);			
			}
			else if(
				pEnemyCraft->GetEnemeyType() == FIGEnemyCraft::ENEMY_TYPES_FORMATION &&
				(FIGEnemyFormationCraft::FORMATION_TYPE)pEnemyInfo->FormationEnumInt > FIGEnemyFormationCraft::FORMATION_NONE
				)
			{
				((FIGEnemyFormationCraft*)pEnemyCraft)->Setup((
															FIGEnemyFormationCraft::FORMATION_TYPE)pEnemyInfo->FormationEnumInt,
															Index,
															pEnemyInfo->Count
															);
			}

			pEnemyCraft->ReSpawn();
		}
		
		Index++;

	}
}

FIGCraft*		FIGEnemyCollection::GetAirCraftByIndex(int Index)
{
	return m_Enemies[Index];
}

bool			FIGEnemyCollection::HitTest(FIGBullet* pBullet)
{
	for(unsigned int i = 0; i < m_Enemies.size(); i++)
	{
		FIGEnemyCraft*  EnemyCraft = m_Enemies[i];
		if( EnemyCraft->HitTest(pBullet))
		{
			return true;
		}
	}

	return false;
}


FIGEnemyCraft*			FIGEnemyCollection::CreateEnemyCraft(const FIGLevel::EnemyInfo* pEnemyInfo)
{
	FIGEnemyCraft::ENEMY_TYPES EnemyType = ((FIGEnemyCraft::ENEMY_TYPES)(pEnemyInfo->EnemyTypeEnumInt));

	switch(EnemyType)
	{
		case FIGEnemyCraft::ENEMY_TYPES_NORMAL:
			return new FIGEnemyPathCraft(EnemyType);
		break;

		case FIGEnemyCraft::ENEMY_TYPES_TRIANGLE:
			return new FIGEnemyTriangle(EnemyType);
		break;

		case FIGEnemyCraft::ENEMY_TYPES_MINIBOSS_HULK:
			return new FIGMiniBossHulk(EnemyType);
		break;

		case FIGEnemyCraft::ENEMY_TYPES_MINIBOSS_COBRA:
				return new FIGMiniBossCobra(EnemyType);
		break;

		case FIGEnemyCraft::ENEMY_TYPES_MINIBOSS_MEGANITO:
			return new FIGMiniBossMeganito(EnemyType);
		break;

		case FIGEnemyCraft::ENEMY_TYPES_MINIBOSS_FOX:
			return new FIGMiniBossFox(EnemyType);
		break;

		case FIGEnemyCraft::ENEMY_TYPES_MINIBOSS_PRON:
			return new FIGMiniBossPron(EnemyType);

		case FIGEnemyCraft::ENEMY_TYPES_MINIBOSS_PLATO:
			return new FIGMiniBossPlato(EnemyType);

		case FIGEnemyCraft::ENEMY_TYPES_MINIBOSS_SHARK:
			return new FIGMiniBossShark(EnemyType);

		case FIGEnemyCraft::ENEMY_TYPES_MINIBOSS_HADIEZ:
			return new FIGMiniBossHadiez(EnemyType);

		case FIGEnemyCraft::ENEMY_TYPES_MINIBOSS_WOLF:
			return new FIGMiniBossWolf(EnemyType);

		case FIGEnemyCraft::ENEMY_TYPES_MINIBOSS_BOMBER:
			return new FIGMiniBossBomber(EnemyType);

		case FIGEnemyCraft::ENEMY_TYPES_BOSS_HUMMER:
			return new FIGBossHummer(EnemyType);
		break;

		case FIGEnemyCraft::ENEMY_TYPES_BOSS_BEAST:
			return new FIGBossBeast(EnemyType);
		break;

		case FIGEnemyCraft::ENEMY_TYPES_BACKATTACKER:
			return new FIGEnemyNormalBackAttacker(EnemyType);
		break;

		case FIGEnemyCraft::ENEMY_TYPES_BOSS_BOFFER:
			return new FIGBossBoffer(EnemyType);	
		break;

		//case FIGEnemyCraft::ENEMY_TYPES_TEST:
		//	return new FIGEnemyNormalTest(EnemyType);	
		//break;

	
		case FIGEnemyCraft::ENEMY_TYPES_BOSS_DESTORYER:
			return new FIGBossDestoryer(EnemyType);
		break;

		case FIGEnemyCraft::ENEMY_TYPES_BOSS_GYVER:
			return new FIGBossGyver(EnemyType);
		break;

		case FIGEnemyCraft::ENEMY_TYPES_BOSS_EAGLE:
			return new FIGBossEagle(EnemyType);
		break;

		case FIGEnemyCraft::ENEMY_TYPES_BOSS_U14:
			return new FIGBossU14(EnemyType);
		break;

		case FIGEnemyCraft::ENEMY_TYPES_SPACEROCK_SLOW:
			return new FIGSpaceRock(EnemyType , FIGSpaceRock::ROCK_TYPE_SLOW );

		case FIGEnemyCraft::ENEMY_TYPES_SPACEROCK_FAST:
			return new FIGSpaceRock(EnemyType , FIGSpaceRock::ROCK_TYPE_FAST );

		case FIGEnemyCraft::ENEMY_TYPES_SPACEROCK_DECAL:
			return new FIGSpaceRock(EnemyType , FIGSpaceRock::ROCK_TYPE_DECAL );

		case FIGEnemyCraft::ENEMY_TYPES_DRAGON:
			return new FIGEnemyDragon(EnemyType);

		case FIGEnemyCraft::ENEMY_TYPES_FORMATION:
			return new FIGEnemyFormationCraft(EnemyType);

		default:
			break;

	}
	
	return NULL;
}
